<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Drag and Drop in PyQt4</title>
<link rel="stylesheet" href="../format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="PyQt, PyQt4, tutorial, python, drag and drop, Linux">
<meta nam="description" content="Drag and Drop in PyQt4">
<meta name="language" content="de">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">
<meta name="translation" content="manuel stein">
</head>

<body>

<div class="content">

<a href="/" title="Home">Home</a>&nbsp;
<a href=".." title="Home">Contents</a>


<h1>Drag and Drop in PyQt4</h1>


<p>
Dieser Abschnitt des PyQt4-Tutorials beschäftigt sich mt Drag &amp; Drop-Operationen.
</p>

<p>
Innerhalb grafischer Benutzeroberflächen handelt es sich bei Drag-and-Drop um 
das Anklicken und Ziehen eines virtuellen Objekts an eine andere Stelle oder 
auf ein anderes virtuelles Objekt. Es kann verwendet werden, um diverse Arten 
von Aktionen auszulösen oder verschiedene Arten von Verbindungen von zwei 
abstrakten Objekten zu erzeugen. (Quelle: Wikipedia)
</p>

<p>
Drag-and-Drop ist eine der offenkundigsten Funktionen grafischer Benutzeroberflächen 
und erlauben den Nutzern die intuitive Ausführung komplexer Handlungen.
</p>

<p>
Gewöhnlich lassen sich zwei Dinge per Drag-and-Dorp bewegen:  Dateien oder bestimmte
grafische Objekte. Wenn wir ein bild von einer Anwendung in die andere verschieben, 
bewegen wir Binärdaten. Wenn wir einen Tab in Firefox ziehen und andernorts 
ablegen, bewegen wir grafische Komponenten per Drag-and-Drop.
</p>


<h3>Einfaches Drag and Drop</h3>

<p>
Im ersten Beispiel verwenden wir <em>QLineEdit</em> und <em>QPushButton</em>.  
Wir werden Fließtext aus dem Zeilenbearbeitungs-Widget ziehen und auf das Knopf-Widget fallen lassen.
</p>

<pre class="code">
#!/usr/bin/python

# dragdrop.py

import sys
from PyQt4 import QtGui

class Button(QtGui.QPushButton):
    def __init__(self, title, parent):
        QtGui.QPushButton.__init__(self, title, parent)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('text/plain'):
            event.accept()
        else:
            event.ignore() 

    def dropEvent(self, event):
        self.setText(event.mimeData().text()) 


class DragDrop(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)

        self.resize(280, 150)
        self.setWindowTitle('Simple Drag &amp; Drop')

        edit = QtGui.QLineEdit('', self)
        edit.setDragEnabled(True)
        edit.move(30, 65)

        button = Button("Button", self)
        button.move(170, 65)

        screen = QtGui.QDesktopWidget().screenGeometry()
        size =  self.geometry()
        self.move((screen.width()-size.width())/2, 
            (screen.height()-size.height())/2)

app = QtGui.QApplication(sys.argv)
icon = DragDrop()
icon.show()
app.exec_()
</pre>

<p>
Einfache Drag-and-Drop-Operationen.
</p>

<pre class="explanation">
 class Button(QtGui.QPushButton):
     def __init__(self, title, parent):
         QtGui.QPushButton.__init__(self, title, parent)
</pre>

<p>
Um Text auf das <em>QPushButton</em>-Widget fallen lassen zu können, müssen wir 
einige Methoden reimplementieren. Also erzeugen wir unsere eigene Knopf-Klasse, 
die wir von der <em>QPushButton</em>-Klasse ableiten.
</p>

<pre class="explanation">
 self.setAcceptDrops(True)
</pre>

<p>
Wir aktivieren die Drop-Ereignisse des Widgets.
</p>

<pre class="explanation">
 def dragEnterEvent(self, event):
     if event.mimeData().hasFormat('text/plain'):
         event.accept()
     else:
         event.ignore()
</pre>

<p>
Zuerst überschreiben wir die <em>dragEnterEvent()</em>-Methode. Darin  informieren wir
über den von uns akzeptierten Datentyp - in unserem Fall Fließtext.
</p>

<pre class="explanation">
def dropEvent(self, event):
     self.setText(event.mimeData().text())
</pre>

<p>
Durch Überschreiben der <em>dropEvent()</em>-Methode definieren wir, was bei einem Drop-Ereignis 
passiert. In diesem Fall ändern wir den Text des Knopf-Widgets.
</p>

<pre class="explanation">
 edit = QtGui.QLineEdit('', self)
 edit.setDragEnabled(True)
</pre>

<p>
Das <em>QLineEdit</em>-Widget verfügt über integrierte Unterstützung für Drag-Operationen. 
Daher müssen wir lediglich die <em>setDragEnabled()</em>-Methode aufrufen, um diesen zu aktivieren.
</p>

<img src="../images/simpledd.png" alt="Einfaches Drag &amp; Drop">
<p class="figure">Abbildung: Einfaches Drag &amp; Drop</p>

<h3>Drag &amp; drop mit einem Knopf-Widget</h3>

<p>
In den folgenden Beispielen demonstrieren wir, wie man Drag-and-Drop auf ein Knopf-Widget anwenden kann.
</p>

<pre class="code">
#!/usr/bin/python

# dragbutton.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore

class Button(QtGui.QPushButton):
    def __init__(self, title, parent):
        QtGui.QPushButton.__init__(self, title, parent)

    def mouseMoveEvent(self, event):

        if event.buttons() != QtCore.Qt.RightButton:
            return

        mimeData = QtCore.QMimeData()

        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(event.pos() - self.rect().topLeft())

        dropAction = drag.start(QtCore.Qt.MoveAction)

        if dropAction == QtCore.Qt.MoveAction:
            self.close()


    def mousePressEvent(self, event):
        QtGui.QPushButton.mousePressEvent(self, event)
        if event.button() == QtCore.Qt.LeftButton:
            print 'press'



class DragButton(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)

        self.resize(280, 150)
        self.setWindowTitle('Click or Move')
        self.setAcceptDrops(True)

        self.button = Button('Button', self)
        self.button.move(100, 65)


        screen = QtGui.QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2, 
            (screen.height()-size.height())/2)


    def dragEnterEvent(self, event):
        event.accept()

    def dropEvent(self, event):

        position = event.pos()
        button = Button('Button', self)
        
        button.move(position)
        button.show()

        event.setDropAction(QtCore.Qt.MoveAction)
        event.accept()


app = QtGui.QApplication(sys.argv)
db = DragButton()
db.show()
app.exec_()
</pre>

<p>
In unserem Code-Beispiel haben wir einen <em>QPushButton</em> im Fenster. Wenn wir auf den Knopf 
mit der linken Maustaste klicken, erscheint in der Konsole 'press'. Durch Rechtsklicken und 
bewegen des Knopfs, erzeugen wir eine Drag-and-Drop-Operation mit dem Knopf-Widget durch.
</p>

<pre class="explanation">
 class Button(QtGui.QPushButton):
     def __init__(self, title, parent):
         QtGui.QPushButton.__init__(self, title, parent)
</pre>

<p>
Wir erzeugen eine Knopf-Klasse, die wir vom <em>QPushButton</em> ableiten. 
Außerdem überschreiben wir zwei Methoden dieses Widgets: <em>mouseMoveEvent()</em> und 
<em>mousePressEvent()</em>. Das <em>mouseMoveEvent()</em> ist der Ort, an dem die Drag-and-Drop-Operation beginnt.
</p>

<pre class="explanation">
 if event.buttons() != QtCore.Qt.RightButton:
     return
</pre>

<p>
Hier entscheidne wir, dass wir Drag-and-Drop nur mit der rechten Maustaste 
ausgeführt werden kann. Die linke Maustaste ist dafür reserviert, den Knopf zu drücken.
</p>

<pre class="explanation">
 mimeData = QtCore.QMimeData()

 drag = QtGui.QDrag(self)
 drag.setMimeData(mimeData)
 drag.setHotSpot(event.pos() - self.rect().topLeft())
</pre>

<p>
Hier erzeugen wir ein <em>QDrag</em>-Objekt.
</p>

<pre class="explanation">
 dropAction = drag.start(QtCore.Qt.MoveAction)

 if dropAction == QtCore.Qt.MoveAction:
     self.close()
</pre>

<p>
Die <em>start()</em>-Methode des Drag-Objekts startet die Drag-and-Drop-Operation. 
Wenn wir eine Move-Drop-Aktion durchführen, zerstören wir das Knopf-Widget. 
Technisch ausgedrückt zerstören wir ein Widget an der gegenwärtigen Position 
und wiedererzeugen es an einer neuen.
</p>

<pre class="explanation">
 def mousePressEvent(self, event):
     QtGui.QPushButton.mousePressEvent(self, event)
     if event.button() == QtCore.Qt.LeftButton:
         print 'press'
</pre>

<p>
Wir geben 'press' in der Konsole aus, wenn wir mit auf den Knopf linksklicken. 
Beachten Sie, dass wir dabei auch die <em>mousePressEvent()</em>-Methode des 
Elternelements aufrufen. Andernfalls würden wir nicht sehen können, dass der Knopf gedrückt wurde.
</p>

<pre class="explanation">
 position = event.pos()
 button = Button('Close', self)
 button.move(position)
 button.show()
</pre>

<p>
In der <em>dropEvent()</em>-Methode programmieren wir, was passiert, nachdem wir 
die Maustaste loslassen und die Drop-Operation beenden.
In unserem Beispiel erzeugen wir ein neues Knopf-Widget an der gegenwärtigen 
Position des Mauszeigers.
</p>

<pre class="explanation">
 event.setDropAction(QtCore.Qt.MoveAction)
 event.accept()
</pre>

<p>
Wir legen die Art der Drop-Aktion fest, in unserem Fall eine Move-Aktion.
</p>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified February 16, 2008  <span class="copyright">&copy; 2007 - 2011 Jan Bodnar</span>
<span class="copyright">Translation © 2009 Manuel Stein</span>
</div>
</div>

</div>
</body> <!-- content -->
</html>


